package com.school.empsys.service.impl;

import com.school.empsys.constants.AttendanceStatus;
import com.school.empsys.constants.LeavePermitStatus;
import com.school.empsys.dto.EmpAttendanceDTO;
import com.school.empsys.dto.EmpLeavePermitDTO;
import com.school.empsys.dto.EmpSalaryDTO;
import com.school.empsys.mapper.*;
import com.school.empsys.model.*;
import com.school.empsys.service.EmpSalaryService;
import com.school.empsys.utils.ComnonUtils;
import com.school.empsys.utils.DateUtils;
import com.school.empsys.utils.UserUtil;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class EmpSalaryServiceImpl implements EmpSalaryService {

    @Value("${working.days}")
    private BigDecimal workingDays;

    @Autowired
    EmpSalaryMapper empSalaryMapper;

    @Autowired
    EmpAttendanceMapper empAttendanceMapper;

    @Autowired
    EmpJobMapper empJobMapper;

    @Autowired
    EmpLeavePermitMapper empLeavePermitMapper;

    @Value("${punchTimeAtWork}")
    private String punchTimeAtWork;

    @Autowired
    UserMapper userMapper;
    
    @Override
    public int count(Map<String, Object> params) {
        return empSalaryMapper.count(params);
    }

    @Override
    public List<EmpSalary> list(Map<String, Object> params, Integer offset, Integer limit) {
        return empSalaryMapper.list(params, offset, limit);
    }

    @Override
    public void save(EmpSalary param) {
        this.calcSalary(param);
        if (param.getId() == null) {
            empSalaryMapper.insert(param);
        } else {
            empSalaryMapper.updateByPrimaryKeySelective(param);
        }
    }

    @Override
    public EmpSalary findOne(Integer id) {
        return empSalaryMapper.selectByPrimaryKey(id);
    }

    @Override
    public EmpSalary init(EmpSalary param) {
        EmpSalaryDTO empSalaryDTO = new EmpSalaryDTO();
        empSalaryDTO.setUserId(param.getUserId().intValue());
        empSalaryDTO.setWageTime(param.getWageTime());
        List<EmpSalary> empSalaryList = empSalaryMapper.selectByEmpSalaryDTO(empSalaryDTO);
        if (!CollectionUtils.isEmpty(empSalaryList)) {
            EmpSalary oldEmpSalary = empSalaryList.get(0);
            BeanUtils.copyProperties(param, oldEmpSalary, ComnonUtils.getNullPropertyNames(param));
            this.calcSalary(oldEmpSalary);
            return oldEmpSalary;
        } else {
            this.calcSalary(param);
            return param;
        }
    }

    public void calcSalary(EmpSalary param) {
        //工资时间
        Date wageTime = DateUtils.string2Date(param.getWageTime(), DateUtils.DateFormatPattern.PATTERN_5);
        //工资时间的月开始、结束时间
        Date monthStartTime = DateUtils.getMonthStartTime(wageTime);
        Date monthEndTime = DateUtils.getMonthEndTime(wageTime);

        //查询该月已保存的工资记录
        EmpAttendanceDTO empAttendance = new EmpAttendanceDTO();
        empAttendance.setStartTime(monthStartTime);
        empAttendance.setEndTime(monthEndTime);
        empAttendance.setUserId(param.getUserId());
        List<EmpAttendance> empAttendanceList = empAttendanceMapper.selectByEmpAttendanceDTO(empAttendance);
        //工作天数
        BigDecimal workDays = new BigDecimal("0");
        if (!CollectionUtils.isEmpty(empAttendanceList)) {
            //打卡正常的考勤
            List<EmpAttendance> normalList = empAttendanceList.stream().filter(x -> AttendanceStatus.NORMAL.getName().equals(x.getStatus())).collect(Collectors.toList());
            //打卡迟到的考勤
            List<EmpAttendance> lateList = empAttendanceList.stream().filter(x -> AttendanceStatus.LATE.getName().equals(x.getStatus())).collect(Collectors.toList());
            //打卡正常的考勤天数
            BigDecimal normalDays = new BigDecimal(normalList.size());
            //打卡迟到的考勤，迟到小于4小时的，算半天工资，超过4小时的，不算当日工资
            List<EmpAttendance> lateHalfDayList = lateList.stream().filter(x -> x.getPunchTimeAfterWork() != null).filter(x -> {
                Date dateWork = DateUtils.date2DateTime(x.getDate(), punchTimeAtWork);
                BigDecimal differHour = DateUtils.dateDifferHours(x.getPunchTimeAtWork(), dateWork);
                return new BigDecimal("4").compareTo(differHour) < 0;
            }).collect(Collectors.toList());

            workDays = workDays.add(normalDays.add(new BigDecimal(lateHalfDayList.size() * 0.5)));
        }

        //请假天数
        EmpLeavePermitDTO permitDTO = new EmpLeavePermitDTO();
        permitDTO.setUserId(param.getUserId());
        permitDTO.setStartTime(monthStartTime);
        permitDTO.setEndTime(monthEndTime);
        permitDTO.setStatus(LeavePermitStatus.PASS.getName());
        List<EmpLeavePermit> empLeavePermitList = empLeavePermitMapper.selectByEmpLeavePermitDTO(permitDTO);
        param.setLeaveDays(empLeavePermitList.size());

        //打卡天数
        BigDecimal attendanceDays = new BigDecimal(empAttendanceList.size());
        param.setAttendanceDays(attendanceDays.intValue());
        param.setAbsenceDays(0);
        //如果打卡天数小于工作日时间
        if (attendanceDays.compareTo(workingDays) < 0) {
            //缺席天数=工作天数-打卡天数
            param.setAbsenceDays(workingDays.subtract(attendanceDays).intValue());
        }

        User user = userMapper.selectByPrimaryKey(param.getUserId());
        EmpJob empJob = empJobMapper.selectByPrimaryKey(user.getJobId());
        //工资 = (底薪 + 奖金 + 提成) - 罚款
        param.setBasicSalary(empJob.getBasicSalary());
        BigDecimal basicSalary = empJob.getDailySalary().multiply(workDays);
        BigDecimal add = basicSalary.add(ComnonUtils.getBigDecimal(param.getBonus())).add(ComnonUtils.getBigDecimal(param.getCommission()));
        param.setActualSalary(add.subtract(ComnonUtils.getBigDecimal(param.getFines())));
    }

    @Override
    public List<EmpSalary> selectByEmpSalaryDTO(EmpSalaryDTO param) {
        return empSalaryMapper.selectByEmpSalaryDTO(param);
    }
}
